import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import com.sun.net.httpserver.*;

import algos.*;
import utils.*;
import static utils.Common.*;

public class Server implements Runnable {
    
    public static final Object lock = new Object();
    public static HttpServer server;
    public static UserEngine engine;
    
    static {
        try {
            /*
            List<Pair<String, Double>> ngf = newArrayList();
            ngf.add(makePair("/home/udalov/completion_server/1grams", 0.000000000001));
            ngf.add(makePair("/home/udalov/completion_server/2grams", 0.0000001));
            ngf.add(makePair("/home/udalov/completion_server/3grams", 0.999999899999));
            engine = Engine.create(ngf);
            System.out.println("engine created");
            */
            List<String> ngf2 = newArrayList();
            ngf2.add("/home/udalov/completion_server/1grams");
            ngf2.add("/home/udalov/completion_server/2grams");
            ngf2.add("/home/udalov/completion_server/3grams");
            engine = UserEngine.create(ngf2);
            List<Double> coreCoefs = newArrayList();
            List<Double> userCoefs = newArrayList();
            coreCoefs.add(0.000000000001);
            coreCoefs.add(0.0000001);
            coreCoefs.add(0.199999899999);
            userCoefs.add(0.1);
            userCoefs.add(0.1);
            userCoefs.add(0.6);
            engine.setCoefs(coreCoefs, userCoefs);
            System.out.println("engine created");
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
    
    private class MyHandler implements HttpHandler {
        private String parseParamFromURI(String uri, String param) throws UnsupportedEncodingException {
            int y = uri.indexOf('?');
            if (y < 0) return "";
            uri = uri.substring(y + 1);
            String[] ss = uri.split("&");
            for (String s : ss) {
                int x = s.indexOf('=');
                if (s.substring(0, x).equals(param)) {
                    return URLDecoder.decode(s.substring(x + 1), "UTF-8");
                }
            }
            return "";
        }
        private String go(String input, boolean firstOnly, int user) {
            String[] words = input.split(" +");
            StringBuilder output = new StringBuilder();
            for (int i = 0; i < words.length; i++) {
                words[i] = words[i].toLowerCase();
            }
            /*
            output.append("Words in your input:\n");
            for (String word : words) {
                Integer x = part.get(word);
                char c = x != null ? OldVocabulary.PART_STR.charAt(x) : ' ';
                output.append("  ").append(c).append(' ').append(word).append('\n');
            }
            */
            List<String> wordsList = newArrayList();
            String prefix;
            if (input.charAt(input.length() - 1) == ' ') {
                for (int i = 0; i < words.length; i++) {
                    wordsList.add(words[i]);
                }
                prefix = "";
            } else {
                for (int i = 0; i < words.length - 1; i++) {
                    wordsList.add(words[i]);
                }
                prefix = words[words.length - 1];
            }
            List<Pair<Double, String>> l;
            synchronized (lock) {
                l = engine.get(wordsList, prefix, user);
            }
            if (firstOnly) {
                if (!l.isEmpty()) output.append(l.get(0).second);
            } else {
                for (Pair<Double, String> p : l) {
                    output.append(String.format("  %.15f  %s%n", p.first, p.second));
                }
            }
            return output.toString();
        }
        public void handle(HttpExchange exchange) throws IOException {
            String requestMethod = exchange.getRequestMethod();
            if (!requestMethod.equalsIgnoreCase("GET")) return;
            String uri = exchange.getRequestURI().toString();
            System.out.println(System.currentTimeMillis() + " " + exchange.getRemoteAddress() + " " + uri);
            String input = parseParamFromURI(uri, "s");
            boolean firstOnly = parseParamFromURI(uri, "firstOnly").length() > 0;
            String callback = parseParamFromURI(uri, "callback");
            OutputStream responseBody = exchange.getResponseBody();
            String output = go(input, firstOnly, Math.abs(exchange.getRemoteAddress().getHostName().toString().hashCode()) % 16384);
            if (callback.length() > 0) {
                output = callback + "({\"s\" : \"" + output + "\"});";
                exchange.getResponseHeaders().set("Content-Type", "text/javascript");
            } else {
                exchange.getResponseHeaders().set("Content-Type", "text/plain");
            }
            exchange.getResponseHeaders().set("Connection", "close");
            exchange.sendResponseHeaders(200, output.length());
            responseBody.write(output.getBytes());
            responseBody.close();
            exchange.close();
            System.out.println(" input: " + input);
            System.out.println("output: " + output);
        }
    }

    public void restart() throws IOException {
        if (server != null) server.stop(0);
        InetSocketAddress addr = new InetSocketAddress(8089);
        server = HttpServer.create(addr, 0);
        server.createContext("/", new MyHandler());
        server.setExecutor(Executors.newCachedThreadPool());
        server.start();
    }
    
    public void run() {
        try {
            restart();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        new Thread(new Server()).start();
    }

}
